use std::fmt::Debug;
use async_trait::async_trait;
use futures::channel::mpsc::Receiver;
use thiserror::Error;
use crate::define::UsbError::Unknown;


#[derive(Error, Debug)]
pub enum UsbError {
    #[error("unknown error: {0}")]
    Unknown(String),
}

#[cfg(windows)]
impl  From<windows::core::Error> for UsbError{
    fn from(value: windows::core::Error) -> Self {
        let msg = value.message().to_string_lossy();
        Unknown(msg)
    }
}

pub enum UsbControlRecipient {
    Device,
    SpecifiedInterface,
    Endpoint,
    Other,
    DefaultInterface
}
impl Into<u32> for UsbControlRecipient {
    fn into(self) -> u32 {
        match self {
            UsbControlRecipient::Device => 0x00,
            UsbControlRecipient::SpecifiedInterface => 0x01,
            UsbControlRecipient::Endpoint => 0x02,
            UsbControlRecipient::Other =>  0x03,
            UsbControlRecipient::DefaultInterface => 0x04
        }
    }
}
pub enum UsbControlTransferType {
    Standard,
    Class,
    Vendor,
}
pub struct UsbControlRequestType{
    pub recipient: UsbControlRecipient,
    pub control_transfer_type: UsbControlTransferType,
}
pub struct ControlTransferRequest{
    pub request_type: UsbControlRequestType,
    pub request: u8,
    pub value: u16,
    pub index: u16,
    pub data: Vec<u8>,
    pub len: u32
}

impl Default for ControlTransferRequest {
    fn default() -> Self {
        Self{
            request_type: UsbControlRequestType {
                recipient: UsbControlRecipient::Device,
                control_transfer_type: UsbControlTransferType::Standard,
            },
            request: 0,
            value: 0,
            index: 0,
            data: vec![],
            len: 0,
        }
    }
}

pub type MResult<T> = Result<T, UsbError>;


pub trait UsbInterface {
    fn number(&self)->MResult<usize>;
    fn get_bulk_in_pipes(&self)->MResult<Vec<Box<dyn BulkInPipe>>>;
    fn get_bulk_out_pipes(&self)->MResult<Vec<Box<dyn BulkOutPipe>>>;
    fn open_bulk_in_channel(&self, package_len: usize, endpoint: usize)->MResult<Receiver<Vec<u8>>>;

}

#[async_trait]
pub trait BulkInPipe{
    async fn read(&mut self, data: &mut [u8])->MResult<usize>;
}

pub trait BulkOutPipe{

}

#[async_trait]
pub trait Device: Debug + Send{
    fn get_vid(&self)->u64;
    fn get_pid(&self)->u64;
    fn get_name(&self)->String;
    async fn open(&mut self)-> MResult<()>;
    async fn control_transfer_in(&self, request: ControlTransferRequest)-> MResult<Vec<u8>>;
    async fn control_transfer_out(&self, request: ControlTransferRequest)-> MResult<usize>;
    fn interface_count(&self)-> MResult<usize>;
    fn interface_get(&self, index: usize)-> MResult<Box<dyn UsbInterface>>;
    fn interface_default(&self)-> MResult<Box<dyn UsbInterface>>;
}

#[async_trait]
pub trait OsManager: Send{
    async fn device_find(&self, vid: Option<u64>, pid: Option<u64>
        )->MResult<Vec<Box<dyn Device>>>;
}